package com.maxd.service.selfWXPay;

import com.maxd.adapter.LoginUserHolder;
import com.maxd.model.PayRecord;
import com.maxd.service.common.ICommonService;
import com.maxd.service.pay.IPayRecordService;
import com.maxd.utils.JsonUtils;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAPublicKeyConfig;
import com.wechat.pay.java.core.notification.*;
import com.wechat.pay.java.core.util.GsonUtil;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;

@Service
public class WxPayV3ServiceImpl implements WxPayV3Service {

    private static final BigDecimal HUNDRED = new BigDecimal(100);

    private static final String descPrefix = "戎威少年 ";
    private static final Logger log = LoggerFactory.getLogger(WxPayV3ServiceImpl.class);

    private JsapiServiceExtension jsapiService;

    @Autowired
    private ICommonService commonService;

    @Value("${wx.pay.callBackUrl}")
    private String callBackUrl;

    @Autowired
    private IPayRecordService payRecordService;

    /**
     * 具体参数参考：https://pay.weixin.qq.com/doc/v3/merchant/4012791897
     * @param payRecord
     * @return
     */
    @Override
    @Transactional
    public PrepayWithRequestPaymentResponse prepayJsapi(PayRecord payRecord) {
        initJsapiService(false);
        String appId = commonService.findByTypeCache(45).getValue();
        String merchantId = commonService.findByTypeCache(76).getValue();
        String callBackDomain = commonService.findByTypeCache(19).getValue();
        String fullUrl = callBackDomain + callBackUrl;

        PrepayRequest request = new PrepayRequest();
        request.setAppid(appId);
        request.setMchid(merchantId);
        request.setNotifyUrl(fullUrl);
        // 描述
        request.setDescription(payRecord.getDescription());
        // 金额
        Amount amount = new Amount();
        amount.setTotal(payRecord.getPayAmount().multiply(HUNDRED).intValue());
        request.setAmount(amount);
        // 付款人
        Payer payer = new Payer();
        payer.setOpenid(LoginUserHolder.getUserInfo().getMpId());
        request.setPayer(payer);
        // 流水号
        request.setOutTradeNo(payRecord.getPaySeq());
        log.info("调用小程序支付预下单，请求参数为:{}", GsonUtil.toJson(request));
        PrepayWithRequestPaymentResponse response = jsapiService.prepayWithRequestPayment(request);
        log.info("调用小程序支付预下单，返回结果为:{}", GsonUtil.toJson(response));
        // 更新状态为1-预下单完成
        payRecordService.updateStatus(payRecord.getPaySeq(), "1");

        return response;
    }

    /**
     * 支付结果回调，参考https://pay.weixin.qq.com/doc/v3/merchant/4012791861
     * @param request
     * @return
     * @throws Exception
     */
    @Override
    public Transaction payNotice(HttpServletRequest request) throws Exception {
        log.info("接收微信回调通知...");
        // 获取回传信息
        String wechatSignature = request.getHeader("Wechatpay-Signature");
        String wechatPaySerial = request.getHeader("Wechatpay-Serial");
        String wechatpayNonce = request.getHeader("Wechatpay-Nonce");
        String wechatSignatureType = request.getHeader("Wechatpay-Signature-Type");
        String wechatTimestamp = request.getHeader("Wechatpay-Timestamp");

        ServletInputStream inputStream = request.getInputStream();
        byte[] bytes = IOUtils.toByteArray(inputStream);
        log.info("接收到的body字节数为:{}", bytes.length);
        String body = new String(bytes, StandardCharsets.UTF_8);
        log.info("接收微信回调通知，body为:{}", body);
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(wechatPaySerial)
                .nonce(wechatpayNonce)
                .signature(wechatSignature)
                .signType(wechatSignatureType)
                .timestamp(wechatTimestamp)
                .body(body)
                .build();

        String publicKeyPath = commonService.findByTypeCache(312).getValue();
        String publicKeyId = commonService.findByTypeCache(313).getValue();
        String apiV3Key = commonService.findByTypeCache(314).getValue();

        NotificationConfig config = new RSAPublicKeyNotificationConfig.Builder()
                .publicKeyFromPath(publicKeyPath)
                .publicKeyId(publicKeyId)
                .apiV3Key(apiV3Key)
                .build();

//        NotificationConfig config = new RSACombinedNotificationConfig.Builder()
//                .merchantId("1683893561")
//                .privateKeyFromPath("/appdata/cert/wxpay/old/wechatpay_773D56AD3B8AD2C875BF261B319C73EF9414B78D.pem")
//                .merchantSerialNumber("6AB7A6156F92BCA304E64E98F1AB6A47BAD46ABF")
//                .publicKeyFromPath(publicKeyPath)
//                .publicKeyId(publicKeyId)
//                .apiV3Key(apiV3Key)
//                .build();

        NotificationParser parser = new NotificationParser(config);
        // 以支付通知回调为例，验签、解密并转换成 Transaction
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        log.info("接收微信回调通知，解析后的结果为:{}", transaction);
        return transaction;
    }

    @Override
    public com.wechat.pay.java.service.payments.model.Transaction queryPayResult(String paySeq) {
        initJsapiService(false);

        String merchantId = commonService.findByTypeCache(76).getValue();

        QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
        request.setMchid(merchantId);
        request.setOutTradeNo(paySeq);

        log.info("查询微信支付结果，入参为:{}", JsonUtils.toJsonString(request));
        com.wechat.pay.java.service.payments.model.Transaction transaction = jsapiService.queryOrderByOutTradeNo(request);
        log.info("查询微信支付结果，返回为:{}", JsonUtils.toJsonString(transaction));
        return transaction;
    }

    /**
     * 微信支付关闭订单：https://pay.weixin.qq.com/doc/v3/merchant/4012791860
     * @param paySeq
     */
    @Override
    public void closeOrder(String paySeq) {
        initJsapiService(false);
        String merchantId = commonService.findByTypeCache(76).getValue();

        CloseOrderRequest request = new CloseOrderRequest();
        request.setMchid(merchantId);
        request.setOutTradeNo(paySeq);
        log.info("微信支付关闭订单，入参:{}", request);
        jsapiService.closeOrder(request);
    }

    public synchronized JsapiServiceExtension initJsapiService(boolean reload) {
        if(reload || jsapiService == null) {
            String merchantId = commonService.findByTypeCache(76).getValue();
            String privateKeyPath = commonService.findByTypeCache(310).getValue();
            String merchantSerialNumber = commonService.findByTypeCache(311).getValue();
            String publicKeyPath = commonService.findByTypeCache(312).getValue();
            String publicKeyId = commonService.findByTypeCache(313).getValue();
            String apiV3Key = commonService.findByTypeCache(314).getValue();

            Config config = new RSAPublicKeyConfig.Builder()
                            .merchantId(merchantId)
                            .privateKeyFromPath(privateKeyPath)
                            .publicKeyFromPath(publicKeyPath)
                            .publicKeyId(publicKeyId)
                            .merchantSerialNumber(merchantSerialNumber)
                            .apiV3Key(apiV3Key)
                            .build();
            jsapiService = new JsapiServiceExtension.Builder().config(config).build();
        }
        return jsapiService;
    }

}
